#ifndef YHAIDA_LOGGING_H
#define YHAIDA_LOGGING_H
#include "LogStream.h"
#include "../datetime/Timestamp.h"
#include "../base/Utils.h"
namespace yhaida
{
    class Logging : yhaida::Utils::nocapyable
    {
    public:
        enum LogLevel
        {
            TRACE,
            DEBUG,
            INFO,
            WARN,
            ERROR,
            FATAL,
            NUM_LOG_LEVELS, //这个是为了表明enum的size.
        };

    public:
        // Impl(LogLevel level, int savedErrno, const char *file, int line);
        Logging(const char *file, int line);
        Logging(int savedErrno, const char *file, int line);
        Logging(LogLevel level, const char *file, int line);
        Logging(LogLevel level, const char *file, int line, const char *func);

        ~Logging();

        LogStream &stream() { return _impl._stream; } //_stream中定义了operator<<
        /*
            统一的操作用static
        */
        static LogLevel logLevel();
        static void setLogLevel(LogLevel level);

        typedef void (*OutputFunc)(const char *str, int length);
        typedef void (*FlushFunc)();
        static void setOutput(OutputFunc);
        static void setFlush(FlushFunc);

    private:
        /*
            格式化输入：日期 时间 微妙 线程 级别（指函数仅在TRACE与DEBUG模式）正文 - 源文件：行号
        */
        class Impl : yhaida::Utils::nocapyable
        {
        public:
            typedef Logging::LogLevel LogLevel;
            // impl_(level, 0, file, line)
            Impl(LogLevel level, int savedErrno, const char *file, int line);
            ~Impl() = default;
            void formatTime();
            void finish();

        public:
            Timestamp _time;
            LogLevel _level;
            LogStream _stream;

            int _line;
            const char *_fullName;
            const char *_baseName;
        };

    private:
        Impl _impl;
    };
    //全局变量
    // extern Logging::LogLevel global_logLevel;
    // 已经给出了接口
    // extern Logging::FlushFunc global_outPut;
    // extern Logging::OutputFunc global_flush;
    extern const char *strerror_tl(int savedErrno);

#define LOG_TRACE if (yhaida::Logging::logLevel() <= yhaida::Logging::TRACE)\
yhaida::Logging(yhaida::Logging::LogLevel::TRACE, __FILE__, __LINE__, __func__).stream()
#define LOG_DEBUG if (yhaida::Logging::logLevel() <= yhaida::Logging::DEBUG)\
yhaida::Logging(yhaida::Logging::LogLevel::DEBUG, __FILE__, __LINE__, __func__).stream()
#define LOG_INFO if (yhaida::Logging::logLevel() <= yhaida::Logging::INFO)\
yhaida::Logging(__FILE__, __LINE__).stream()
#define LOG_WARN yhaida::Logging(yhaida::Logging::LogLevel::WARN, __FILE__, __LINE__).stream()
#define LOG_ERROR yhaida::Logging(yhaida::Logging::LogLevel::ERROR, __FILE__, __LINE__).stream()
#define LOG_FATAL yhaida::Logging(yhaida::Logging::LogLevel::FATAL, __FILE__, __LINE__).stream()
#define LOG_SYSERR yhaida::Logging(false, __FILE__, __LINE__).stream()
#define LOG_SYSFATAL yhaida::Logging(true, __FILE__, __LINE__).stream()

    // extern const char *strerror_tl(int savedErrno);

#define CHECK_NOTNULL(val) yhaida::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))

    // A small helper for CHECK_NOTNULL().
    template <typename T>
    T *CheckNotNull(const char *file, int line, const char *names, T *ptr)
    {
        if (ptr == NULL)
        {
            Logging(yhaida::Logging::LogLevel::FATAL, file, line).stream() << names;
        }
        return ptr;
    }

    //     template <typename To, typename From>
    //     inline To implicit_cast(From const &f)
    //     {
    //         return f;
    //     }

}

#endif